package fn

import "fmt"

//1. 关键字 defer 用于注册延迟调用。
//2. 这些调用直到 return 前才被执。因此，可以用来做资源清理。
//3. 多个defer语句，按先进后出的方式执行。
//4. defer语句中的变量，在defer声明时就决定了

func init() {

	fmt.Println("fn init   2------")

}

func clean(i int8) {
	fmt.Println(i)
}

func deferFnArgs() {
	fmt.Printf("---- run  defer------\n")

	//defer 函数调用的参数会被保存起来，但是不执行。也就是拷贝了一份
	var i int8 = 1
	for ; i < 8; i++ {
		defer clean(i)
	}

	fmt.Printf("-------\n")
}

type Test struct {
	name   string
	closed bool
}

func (t *Test) Close() {
	t.closed = true
	fmt.Println(t.name, " closed")
}

var ts = []Test{{name: "a", closed: false}, {name: "b", closed: false}, {name: "c", closed: false}}

func deferFunction1() {

	//输出并不会像我们预计的输出c b a,而是输出c c c,这是range变量t只是拷贝一份值
	for _, t := range ts {
		//由于close()附加类型是指针,所以这里拷贝的是t的地址
		defer t.Close()
	}
}

func deferFunction2() {
	for _, t := range ts {
		//这里虽然t2不同了，但是还是拷贝的t,对原数组的元素不起作用
		t2 := t
		//这里每次都是新的t2，所以拷贝的虽是t2地址,但每次地址不同
		defer t2.Close()
	}

}

//正确写法
func deferFunction3() {
	//不用range所以不会拷贝
	for i := 0; i < len(ts); i++ {
		//这里取地址所以不会拷贝结构体
		t2 := &ts[i]
		defer t2.Close()
	}

}

func RunDefer() {
	//deferFnArgs()
	deferFunction1()
	//deferFunction2()
	//deferFunction3()
	for _, t := range ts {
		println(t.name, "->", t.closed)
	}

}
